package com.liuqianfei.markme.rules.inline;

import com.liuqianfei.markme.common.Utils;
import com.liuqianfei.markme.core.Token;
import com.liuqianfei.markme.helpers.MarkMeHelper;
import com.liuqianfei.markme.helpers.Result;
import com.liuqianfei.markme.rules.AbstractState;
import com.liuqianfei.markme.rules.IAction;
import com.liuqianfei.markme.rules.Reference;
import com.liuqianfei.markme.rules.StateInline;
import com.liuqianfei.util.StringUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author liuqianfei
 */
public class ImageAction implements IAction
{
    @Override
    public boolean parse(AbstractState state, boolean silent, int startLine, int endLine)
    {
        Map<String, String> attrs = new HashMap<>();
        char code;
        String content;
        String label = null;
        int labelEnd;
        int labelStart;
        int pos;
        Reference ref;
        Result res;
        String title;
        Token token;
        List<Token> tokens = new ArrayList<>();
        int start;
        String href = null;
        int oldPos = state.getPos();
        int max = state.getPosMax();

        if (state.getSrc().charAt(state.getPos()) != 0x21/* ! */)
            return false;

        // FIXME: 2016/12/15 java.lang.StringIndexOutOfBoundsException: String index out of range: 18
//        if (state.getSrc().charAt(state.getPos() + 1) != 0x5B/* [ */)
//            return false;

        labelStart = state.getPos() + 2;
        labelEnd = MarkMeHelper.parseLinkLabel((StateInline) state, state.getPos() + 1, false);

        // parser failed to find ']', so it's not a valid link
        if (labelEnd < 0)
            return false;

        pos = labelEnd + 1;
        if (pos < max && state.getSrc().charAt(pos) == 0x28/* ( */)
        {
            //
            // Inline link
            //

            // [link](  <href>  "title"  )
            //        ^^ skipping these spaces
            pos++;
            for (; pos < max; pos++)
            {
                code = state.getSrc().charAt(pos);
                if (!Utils.isSpace(code) && code != 0x0A)
                    break;
            }
            if (pos >= max)
                return false;

            // [link](  <href>  "title"  )
            //          ^^^^^^ parsing link destination
            start = pos;
            res = MarkMeHelper.parseLinkDestination(state.getSrc(), pos, state.getPosMax());
            if (res.ok)
            {
                href = state.getMd().normalizeLink(res.str);
                if (state.getMd().validateLink(href))
                    pos = res.pos;
                else
                    href = "";
            }

            // [link](  <href>  "title"  )
            //                ^^ skipping these spaces
            start = pos;
            for (; pos < max; pos++)
            {
                code = state.getSrc().charAt(pos);
                if (!Utils.isSpace(code) && code != 0x0A)
                    break;
            }

            // [link](  <href>  "title"  )
            //                  ^^^^^^^ parsing link title
            res = MarkMeHelper.parseLinkTitle(state.getSrc(), pos, state.getPosMax());
            if (pos < max && start != pos && res.ok)
            {
                title = res.str;
                pos = res.pos;

                // [link](  <href>  "title"  )
                //                         ^^ skipping these spaces
                for (; pos < max; pos++)
                {
                    code = state.getSrc().charAt(pos);
                    if (!Utils.isSpace(code) && code != 0x0A)
                        break;
                }
            }
            else
            {
                title = "";
            }

            if (pos >= max || state.getSrc().charAt(pos) != 0x29/* ) */)
            {
                state.setPos(oldPos);
                return false;
            }
            pos++;
        }
        else
        {
            //
            // Link reference
            //
            if (null == state.getEnv().references)
                return false;

            if (pos < max && state.getSrc().charAt(pos) == 0x5B/* [ */)
            {
                start = pos + 1;
                pos = MarkMeHelper.parseLinkLabel((StateInline) state, pos, false);
                if (pos >= 0)
                    label = StringUtil.slice(state.getSrc(), start, pos++);
                else
                    pos = labelEnd + 1;
            } else {
                pos = labelEnd + 1;
            }

            // covers label === '' and label === undefined
            // (collapsed reference link and shortcut reference link respectively)
            if (StringUtil.isEmpty(label))
                label = StringUtil.slice(state.getSrc(), labelStart, labelEnd);

            ref = state.getEnv().references.get(Utils.normalizeReference(label));
            if (null == ref)
            {
                state.setPos(oldPos);
                return false;
            }
            href = ref.href;
            title = ref.title;
        }

        //
        // We found the end of the link, and know for a fact it's a valid link;
        // so all that's left to do is to call tokenizer.
        //
        if (!silent)
        {
            content = StringUtil.slice(state.getSrc(), labelStart, labelEnd);

            state.getMd().parserInline.parse(content, state.getMd(), state.getEnv(), tokens, null);

            attrs.put("src", href);
            attrs.put("alt", "");
            token          = state.push("image", "img", 0);
            token.attrs    = attrs;
            token.children = tokens;
            token.content  = content;

            if (StringUtil.isNotEmpty(title))
                attrs.put("title", title);
        }

        state.setPos(pos);
        state.setPosMax(max);

        return true;
    }
}
